﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using io = System.IO;
using wf = System.Windows.Forms;
using dw = System.Drawing;
using System.Threading.Tasks;

namespace editor.app
{
    /// <summary>
    /// ImageSplice.xaml 的交互逻辑
    /// </summary>
    public partial class ImageSplice : Window
    {
        class ImageLayer : ContentControl
        {
            Grid _gridRoot = new Grid();
            Image _image = new Image();
            Border _brCentre = null;
            string _fileName = "";
            int _imageX = 0, _imageY = 0, _imageWidth = 0, _imageHeight = 0;

            public int CentreX { get; private set; }
            public int CentreY { get; private set; }

            ImageSplice _imageSplice = null;

            public ImageLayer(ImageSplice imageSplice, string fileName)
            {
                _imageSplice = imageSplice;
                _fileName = fileName;

                SetImage(io.File.ReadAllBytes(_fileName));
                _gridRoot.Children.Add(_image);

                _gridRoot.Children.Add(new Border
                {
                    BorderBrush = new SolidColorBrush(Color2.White(20)),
                    BorderThickness = new Thickness(0, 0, 1, 1)
                });

                _gridRoot.Children.Add(new TextBlock
                {
                    Text = io.Path.GetFileName(fileName),
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Top,
                    Foreground = new SolidColorBrush(Color2.Yellow(50)),
                    FontSize = 12,
                    Margin = new Thickness(4)
                });

                _brCentre = new Border
                {
                    Width = 6,
                    Height = 6,
                    CornerRadius = new CornerRadius(6),
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Top,
                    BorderThickness = new Thickness(1),
                    BorderBrush = new SolidColorBrush(Color2.White()),
                    Background = new SolidColorBrush(Color2.Red(50))
                };
                _gridRoot.Children.Add(_brCentre);

                UpdateCentre();

                Background = new SolidColorBrush(Color2.Transparent());
                Content = _gridRoot;

                MouseLeftButtonDown += new MouseButtonEventHandler(ImageLayer_MouseLeftButtonDown);
                MouseRightButtonDown += new MouseButtonEventHandler(ImageLayer_MouseRightButtonDown);
            }

            void ImageLayer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                var pt = e.GetPosition(this);
                _imageSplice.SetCentre((int)pt.X, (int)pt.Y);
            }
            void ImageLayer_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                ((StackPanel)Parent).Children.Remove(this);
            }

            void SetImage(byte[] bytes)
            {
                var bitmapImage = new BitmapImage();
                bitmapImage.FromBytes(bytes);

                _image.Width = bitmapImage.PixelWidth;
                _image.Height = bitmapImage.PixelHeight;
                _image.Source = bitmapImage;

                _gridRoot.Width = _image.Width;
                _gridRoot.Height = _image.Height;
            }
            void UpdateCentre()
            {
                _brCentre.Margin = new Thickness(CentreX - _brCentre.Width / 2, CentreY - _brCentre.Height / 2, 0, 0);
            }

            int _minX, _minY, _maxWidth, _maxHeight;

            public void SetCentre(int x, int y)
            {
                CentreX = x;
                CentreY = y;
                UpdateCentre();
            }
            public int[] CalcClip()
            {
                var bitmap = new dw.Bitmap(_fileName);

                int minX = -1, minY = -1, maxX = 0, maxY = 0;
                for (int x = 0; x < bitmap.Width; x++)
                {
                    for (int y = 0; y < bitmap.Height; y++)
                    {
                        var color = bitmap.GetPixel(x, y);
                        if (color.A > 0)
                        {
                            if (minX == -1)
                            {
                                minX = x;
                                minY = y;
                            }

                            minX = Math.Min(minX, x);
                            minY = Math.Min(minY, y);

                            maxX = Math.Max(maxX, x);
                            maxY = Math.Max(maxY, y);
                        }
                    }
                }
                _imageX = minX;
                _imageY = minY;
                _imageWidth = maxX - minX;
                _imageHeight = maxY - minY;

                bitmap.Dispose();

                return new int[] { minX, minY, _imageWidth, _imageHeight };
            }
            public new void Clip(int minX, int minY, int maxWidth, int maxHeight)
            {
                _minX = minX;
                _minY = minY;
                _maxWidth = maxWidth;
                _maxHeight = maxHeight;

                using (var bitmap = GetBitmapClip())
                {
                    using (var ms = new io.MemoryStream())
                    {
                        bitmap.Save(ms, dw.Imaging.ImageFormat.Png);

                        Dispatcher.BeginInvoke(new Action(() =>
                        {
                            SetImage(ms.ToArray());
                        }));
                    }
                }
            }
            public dw.Bitmap GetBitmapClip()
            {
                var bitmap = new dw.Bitmap(_fileName);
                var bitmapClip = new dw.Bitmap(_maxWidth + CLIP_MARGIN * 2, _maxHeight + CLIP_MARGIN * 2);
                var g = dw.Graphics.FromImage(bitmapClip);
                g.DrawImage(bitmap,
                    new dw.Rectangle(
                        _imageX - _minX + CLIP_MARGIN,
                        _imageY - _minY + CLIP_MARGIN,
                    _imageWidth, _imageHeight),
                    new dw.Rectangle(_imageX, _imageY, _imageWidth, _imageHeight),
                    dw.GraphicsUnit.Pixel);
                bitmap.Dispose();

                return bitmapClip;
            }
        }

        const int CLIP_MARGIN = 10;

        RImage _rImage = null;
        comm.objst.RPack _rpack = null;
        Dictionary<string, List<int>> _rimageDic = new Dictionary<string, List<int>>();
        int _imageMaxWidth = 0, _imageMaxHeight = 0;

        public ImageSplice(RImage rImage, comm.objst.RPack rpack)
        {
            InitializeComponent();
            this.LoadConfig1();

            _rImage = rImage;
            _rpack = rpack;

            AllowDrop = true;

            btnSave.IsEnabled = false;

            PreviewDrop += new DragEventHandler(ImageSplice_PreviewDrop);
            btnClear.Click += new RoutedEventHandler(btnClear_Click);
            btnClip.Click += new RoutedEventHandler(btnClip_Click);
            btnSave.Click += new RoutedEventHandler(btnSave_Click);
            btnCancel.Click += new RoutedEventHandler(btnCancel_Click);
            lbRImage.SelectionChanged += new SelectionChangedEventHandler(lbRImage_SelectionChanged);
            btnSaveOK.Click += new RoutedEventHandler(btnSaveOK_Click);
        }

        void btnSaveOK_Click(object sender, RoutedEventArgs e)
        {
            gridMask.Visibility = Visibility.Visible;
            tbProc.Text = "";
            var group = getAllGroupImageLayer();
            comm.ThreadHelper.Run(() =>
            {
                var count = 0;
                foreach (var key in _rimageDic.Keys)
                {
                    var ixs = _rimageDic[key];
                    var rImage = _rpack.GetResource<comm.objst.RImage>(key);
                    var max = 0;
                    foreach (var ix in ixs)
                    {
                        max = Math.Max(max, group[ix].Length);
                    }
                    var w = max * _imageMaxWidth;
                    var h = _imageMaxHeight * ixs.Count;
                    if (w > 0 && h > 0)
                    {
                        rImage.Width = w;
                        rImage.Height = h;
                        rImage.FrameList.Clear();
                        using (var bitmap = new dw.Bitmap(w, h))
                        {
                            var g = dw.Graphics.FromImage(bitmap);
                            for (int y = 0, len = ixs.Count; y < len; y++)
                            {
                                var ix = ixs[y];
                                var list = group[ix];
                                for (int x = 0, c = list.Length; x < c; x++)
                                {
                                    var image = list[x];
                                    g.DrawImage(image.GetBitmapClip(), x * _imageMaxWidth, y * _imageMaxHeight);

                                    rImage.FrameList.Add(new comm.objst.RImage.Frame
                                    {
                                        CentreX = image.CentreX,
                                        CentreY = image.CentreY,
                                        X = x * _imageMaxWidth,
                                        Y = y * _imageMaxHeight,
                                        Width = _imageMaxWidth,
                                        Height = _imageMaxHeight
                                    });
                                }
                            }

                            using (var ms = new io.MemoryStream())
                            {
                                bitmap.Save(ms, dw.Imaging.ImageFormat.Png);
                                rImage.ImageBytes = ms.ToArray();
                            }
                        }

                        Dispatcher.BeginInvoke(new Action(() =>
                        {
                            count++;
                            tbProc.Text = "处理中(" + count + "/" + _rimageDic.Count + ")";
                        }));
                    }
                }

                Dispatcher.BeginInvoke(new Action(() =>
                {
                    gridMask.Visibility = Visibility.Collapsed;

                    Close();
                }));
            });
        }
        void lbRImage_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            FillRImage();
        }
        void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            gridSaveBox.Visibility = Visibility.Collapsed;
        }
        void btnSave_Click(object sender, RoutedEventArgs e)
        {
            ShowSaveBox();
        }
        void ImageSplice_PreviewDrop(object sender, DragEventArgs e)
        {
            var paths = (string[])e.Data.GetData(DataFormats.FileDrop);
            var list = new List<string>();
            foreach (var path in paths)
            {
                if (io.File.Exists(path) && io.Path.GetExtension(path).ToLower() == ".png")
                {
                    list.Add(path);
                }
                else if (io.Directory.Exists(path))
                {
                    FillDir(path);
                }
            }
            if (list.Count > 0)
            {
                AddGroup(list.ToArray());
            }
        }
        void btnClear_Click(object sender, RoutedEventArgs e)
        {
            spLayer.Children.Clear();
        }
        void btnClip_Click(object sender, RoutedEventArgs e)
        {
            var list = getAllImageLayer();
            if (list.Length == 0)
            {
                return;
            }
            gridMask.Visibility = Visibility.Visible;
            tbProc.Text = "";

            comm.ThreadHelper.Run(() =>
            {
                var count = 0;
                int minX = -1, minY = -1, maxX = 0, maxY = 0;
                foreach (var image in list)
                {
                    var size = image.CalcClip();
                    if (minX == -1)
                    {
                        minX = size[0];
                        minY = size[1];
                    }

                    minX = Math.Min(minX, size[0]);
                    minY = Math.Min(minY, size[1]);

                    maxX = Math.Max(maxX, size[0] + size[2]);
                    maxY = Math.Max(maxY, size[1] + size[3]);

                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        count++;
                        tbProc.Text = "处理中(" + count + "/" + list.Length + ")";
                    }));
                }
                int maxW = maxX - minX, maxH = maxY - minY;
                _imageMaxWidth = maxW + CLIP_MARGIN * 2;
                _imageMaxHeight = maxH + CLIP_MARGIN * 2;

                //Console.WriteLine(maxW + "," + maxH);

                foreach (var image in list)
                {
                    image.Clip(minX, minY, maxW, maxH);

                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        count++;
                        tbProc.Text = "处理中(" + count + "/" + list.Length + ")";
                    }));
                }

                Dispatcher.BeginInvoke(new Action(() =>
                {
                    gridMask.Visibility = Visibility.Collapsed;
                    btnSave.IsEnabled = true;
                }));
            });
        }

        ImageLayer[] getAllImageLayer()
        {
            var list = new List<ImageLayer>();
            var all = getAllGroupImageLayer();
            foreach (var ls in all)
            {
                foreach (var item in ls)
                {
                    list.Add(item);
                }
            }
            return list.ToArray();
        }
        List<ImageLayer[]> getAllGroupImageLayer()
        {
            var list = new List<ImageLayer[]>();
            foreach (var el in spLayer.Children)
            {
                var ls = new List<ImageLayer>();
                var sp = (StackPanel)el;
                foreach (var item in sp.Children)
                {
                    ls.Add((ImageLayer)item);
                }
                list.Add(ls.ToArray());
            }
            return list;
        }
        void SetCentre(int x, int y)
        {
            var list = getAllImageLayer();
            foreach (var item in list)
            {
                item.SetCentre(x, y);
            }
        }
        void AddGroup(string[] files)
        {
            var sp = new StackPanel
            {
                Orientation = Orientation.Horizontal,
                Margin = new Thickness(0, 0, 0, 10)
            };
            foreach (var fileName in files)
            {
                try
                {
                    var imageLayer = new ImageLayer(this, fileName);
                    sp.Children.Add(imageLayer);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            spLayer.Children.Add(sp);
        }
        void FillDir(string dir)
        {
            var dirs = io.Directory.GetDirectories(dir);
            var files = io.Directory.GetFiles(dir, "*.png");
            foreach (var d in dirs)
            {
                FillDir(d);
            }
            var list = new List<string>();
            foreach (var file in files)
            {
                list.Add(file);
            }
            if (list.Count > 0)
            {
                AddGroup(list.ToArray());
            }
        }
        string GetSelectedRImage()
        {
            if (lbRImage.SelectedIndex != -1)
            {
                var tb = (FrameworkElement)lbRImage.SelectedItem;
                return tb.Tag.ToString();
            }
            return null;
        }
        void ShowSaveBox()
        {
            gridSaveBox.Visibility = Visibility.Visible;

            lbRImage.Items.Clear();
            wpImage.Children.Clear();

            _rimageDic.Clear();

            var keys = _rpack.GetAllResourceKeys(typeof(comm.objst.RImage));
            foreach (var key in keys)
            {
                var rImage = _rpack.GetResource(key);
                lbRImage.Items.Add(new TextBlock { Tag = key, Text = rImage.Name });
            }

            if (lbRImage.Items.Count > 0)
            {
                lbRImage.SelectedIndex = 0;
            }

            for (int i = 0, len = spLayer.Children.Count; i < len; i++)
            {
                var btn = new Button
                {
                    Content = i,
                    Padding = new Thickness(4, 0, 4, 0),
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Margin = new Thickness(0, 0, 4, 4),
                    BorderBrush = new SolidColorBrush(Color2.Black(50))
                };
                var ix = i;
                btn.Click += new RoutedEventHandler((o, e) =>
                {
                    var rimage = GetSelectedRImage();
                    if (rimage != null)
                    {
                        if (!_rimageDic.ContainsKey(rimage))
                        {
                            _rimageDic.Add(rimage, new List<int>());
                        }
                        _rimageDic[rimage].Add(ix);
                        FillRImage();
                    }
                });
                wpImage.Children.Add(btn);
            }

            FillRImage();
        }
        void FillRImage()
        {
            wpSaveImage.Children.Clear();
            var rimage = GetSelectedRImage();
            if (rimage != null && _rimageDic.ContainsKey(rimage))
            {
                var ixs = _rimageDic[rimage];
                var ix2 = -1;
                foreach (var ix in ixs)
                {
                    ix2++;
                    var ix3 = ix2;
                    var btn = new Button
                    {
                        Content = ix,
                        Padding = new Thickness(4, 0, 4, 0),
                        HorizontalAlignment = HorizontalAlignment.Left,
                        Margin = new Thickness(0, 0, 4, 4),
                        BorderBrush = new SolidColorBrush(Color2.Black())
                    };
                    btn.Click += new RoutedEventHandler((o, e) =>
                    {
                        wpSaveImage.IsEnabled = false;
                        ixs.RemoveAt(ix3);
                        FillRImage();
                        wpSaveImage.IsEnabled = true;
                    });
                    wpSaveImage.Children.Add(btn);
                }
            }
        }
    }
}
